<script>
import ajax from './ajax';
import UploadDragger from './upload-dragger.vue';
import SparkMD5 from 'spark-md5'
// import axios from 'axios'
import {checkBigFile} from "@/api/trunk"

function getFileMD5(file) {
  return new Promise((resolve, reject) => {
    const spark = new SparkMD5.ArrayBuffer()
    const fileReader = new FileReader();
    fileReader.onload = (e) => {
      spark.append(e.target.result)
      resolve(spark.end())
    }
    fileReader.onerror = () => {
      reject("")
    }
    fileReader.readAsArrayBuffer(file)
  })
}

export default {
  inject: ['uploader'],
  components: {
    UploadDragger
  },
  props: {
    type: String,
    action: {
      type: String,
      required: true
    },
    name: {
      type: String,
      default: 'file'
    },
    data: Function,
    chunkSize: Number,
    thread: Number,
    headers: Object,
    withCredentials: Boolean,
    multiple: Boolean,
    accept: String,
    onStart: Function,
    onProgress: Function,
    onSuccess: Function,
    onError: Function,
    beforeUpload: Function,
    drag: Boolean,
    onPreview: {
      type: Function,
      default: function () {
      }
    },
    onRemove: {
      type: Function,
      default: function () {
      }
    },
    fileList: Array,
    autoUpload: Boolean,
    listType: String,
    httpRequest: {
      type: Function,
      default: ajax
    },
    disabled: Boolean,
    limit: Number,
    onExceed: Function
  },

  data() {
    return {
      mouseover: false,
      reqs: {}
    };
  },

  methods: {
    isImage(str) {
      return str.indexOf('image') !== -1;
    },
    handleChange(ev) {
      const files = ev.target.files;

      if (!files) return;
      this.uploadFiles(files);
    },
    uploadFiles(files) {
      if (this.limit && this.fileList.length + files.length > this.limit) {
        this.onExceed && this.onExceed(files, this.fileList);
        return;
      }

      let postFiles = Array.prototype.slice.call(files);
      if (!this.multiple) {
        postFiles = postFiles.slice(0, 1);
      }

      if (postFiles.length === 0) {
        return;
      }

      postFiles.forEach(rawFile => {
        this.onStart(rawFile);
        if (this.autoUpload) this.upload(rawFile);
      });
    },
    upload(rawFile) {
      this.$refs.input.value = null;

      if (!this.beforeUpload) {
        return this.post(rawFile);
      }

      const before = this.beforeUpload(rawFile);
      if (before && before.then) {
        before.then(processedFile => {
          const fileType = Object.prototype.toString.call(processedFile);

          if (fileType === '[object File]' || fileType === '[object Blob]') {
            if (fileType === '[object Blob]') {
              processedFile = new File([processedFile], rawFile.name, {
                type: rawFile.type
              });
            }
            for (const p in rawFile) {
              if (rawFile.hasOwnProperty(p)) {
                processedFile[p] = rawFile[p];
              }
            }
            this.post(processedFile);
          } else {
            this.post(rawFile);
          }
        }, () => {
          this.onRemove(null, rawFile);
        });
      } else if (before !== false) {
        this.post(rawFile);
      } else {
        this.onRemove(null, rawFile);
      }
    },
    abort(file) {
      const {reqs} = this;
      if (file) {
        let uid = file;
        if (file.uid) uid = file.uid;
        if (reqs[uid]) {
          // reqs[uid].abort();
          reqs[uid].forEach(item => {
            item.abort();
          })
        }
      } else {
        Object.keys(reqs).forEach((uid) => {
          if (reqs[uid]) {
            // reqs[uid].abort();
            reqs[uid].forEach(item => {
              item.abort();
            })
          }
          delete reqs[uid];
        });
      }
    },
    async post(rawFile) {
      //计算整个大文件hash
      let fileHash = await getFileMD5(rawFile)
      //大文件切片后的数组
      let chunkList = []
      //开始切片
      for (let i = 0; i < rawFile.size; i = i + this.chunkSize) {
        const tmp = rawFile.slice(i, Math.min((i + this.chunkSize), rawFile.size))
        chunkList.push(tmp)
      }
      const {uid} = rawFile;

      // let checkedHash = await axios({
      //   url: 'http://localhost:8080/checkBigFile',
      //   method: "get",
      //   params: {
      //     fileMd5: fileHash,
      //     fileSize: rawFile.size,
      //     chunkSize: this.chunkSize
      //   },
      //   headers: {
      //     ...this.headers
      //   }
      // });
      console.log(rawFile)
      let checkedHash = await checkBigFile({
        fileMd5: fileHash,
        fileSize: rawFile.size,
        chunkSize: this.chunkSize,
        fileName: rawFile.name
      })
      // console.log(checkedHash)
      if (checkedHash.status === 200 && checkedHash.data.code === 1) {
        this.reqs[uid] = checkedHash.data;
        new Promise(resolve => {
          resolve(checkedHash)
        }).then(res => {
          this.onSuccess(res, rawFile);
          delete this.reqs[uid];
        }, err => {
          this.onError(err, rawFile);
          delete this.reqs[uid];
        })
      } else {
        if (checkedHash.data.status === 500) {
          this.onError(checkedHash, rawFile);
          delete this.reqs[uid];
        }
        //计算每个切片的hash
        const chunkHashList = await Promise.all(chunkList.map(async (item) => {
          return await getFileMD5(item)
        }))

        const options = {
          headers: this.headers,
          withCredentials: this.withCredentials,
          file: rawFile,
          data: this.data,
          filename: this.name,
          action: this.action,
          //下面5个是新增的属性
          fileHash: fileHash,
          chunkList: chunkList,
          chunkHashList: chunkHashList,
          chunkSize: this.chunkSize,
          thread: this.thread,
          checkedHash: checkedHash,
          onProgress: e => {
            this.onProgress(e, rawFile);
          },
          onSuccess: res => {
            this.onSuccess(res, rawFile);
            delete this.reqs[uid];
          },
          onError: err => {
            this.onError(err, rawFile);
            delete this.reqs[uid];
          }
        };
        const req = this.httpRequest(options);
        this.reqs[uid] = req;
        if (req && req.then) {
          req.then(options.onSuccess, options.onError);
        }
      }

    }

    ,
    handleClick() {
      if (!this.disabled) {
        this.$refs.input.value = null;
        this.$refs.input.click();
      }
    }
    ,
    handleKeydown(e) {
      if (e.target !== e.currentTarget) return;
      if (e.keyCode === 13 || e.keyCode === 32) {
        this.handleClick();
      }
    }
  },

  render(h) {
    let {
      handleClick,
      drag,
      name,
      handleChange,
      multiple,
      accept,
      listType,
      uploadFiles,
      disabled,
      handleKeydown
    } = this;
    const data = {
      class: {
        'el-upload': true
      },
      on: {
        click: handleClick,
        keydown: handleKeydown
      }
    };
    data.class[`el-upload--${listType}`] = true;
    return (
      <div {...data} tabindex="0">
        {
          drag
            ? <upload-dragger disabled={disabled} on-file={uploadFiles}>{this.$slots.default}</upload-dragger>
            : this.$slots.default
        }
        <input class="el-upload__input" type="file" ref="input" name={name} on-change={handleChange}
               multiple={multiple} accept={accept}></input>
      </div>
    );
  }
};
</script>
